<?php


function getPdio($dbType) {
	
	switch ($dbType) {
		
		case DB_MYSQL	: return new PDIO_MYSQL();
		case DB_ORA		: return new PDIO_ORA();

		default 		: throw new FWerrorException('unhandled database'); 
	}
	
	
}



interface PDIO {
	
	const FETCH_ALL = 'fetch_all';
	
	public function query($sql);
	public function parametricQuery($sql, $data);
	public function close();
	public function callProcedure($pname, &$pvars);
	public function errorInfo();
	public function beginTransaction();
	public function rollBack();
	public function commit();
	
}


class PDIO_MYSQL implements PDIO {
	/**
	 * 
	 * @var PDO
	 */
	private $pdo;
	
	public function __construct() {
		try {
			$this->pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_UNAME, DB_PASS);
			if ($this->pdo == null) {
				throw new PDOException('pdio nullo');
			}
		}  catch (PDOException $e) {
			throw new FWerrorException('Connection failed: ' . $e->getMessage());
		}
	}
	
	
	
	public function query($sql, $mode = PDO::FETCH_ASSOC, $fetch = PDIO::FETCH_ALL) {
		$stmt = $this->pdo->query($sql);
		
		if (!$stmt) {
			throw new DBException('errore stmt: <pre>'.print_r($this->errorInfo(),true).'</pre>');
		}
		
		switch ($fetch) {
			case PDIO::FETCH_ALL: $res = $stmt->fetchAll($mode); $stmt->closeCursor(); break;
			
			default:	$res = $stmt;
		}
		
		return $res;
		
	}
	
	public function parametricQuery($sql, $data, $mode = PDO::FETCH_ASSOC, $fetch = PDIO::FETCH_ALL) {
		
		if ($this->pdo == null) {
			echo 'bumba'; die;
		}
		
		$stmt = $this->pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
		
		if (!$stmt) {
			throw new FWerrorException('errore stmt');
		}

		
		if (!$stmt->execute($data)) {

			throw new FWerrorException('stmt note executed<pre>'.print_r($stmt->errorInfo(), true)."$sql");
		}
		
		switch ($fetch) {
			case PDIO::FETCH_ALL: $res = $stmt->fetchAll($mode); $stmt->closeCursor(); break;
				
			default:	$res = $stmt;
		}
		
		return $res;		
		
	}
	
	public function close() {
		$this->pdo = null;
	}
	
	public function callProcedure($pname, &$pvars) {
		
		$pargs = array();
		foreach ($pvars['in'] as $k => $v) {
			$pargs[] = ':'.$k;
		}
		
		foreach ($pvars['out'] as $k => $v) {
			$pargs[] = '@'.$k;
		}		
		
		$string_args = implode(', ', $pargs);
		$sql = "call ".DB_NAME.".$pname($string_args)";
		$stmt = $this->pdo->prepare($sql);
		$this->bindParams($stmt, $pvars);
		$stmt->execute();
		
		if ($stmt->errorCode() != null) {
			throw new FWerrorException(print_r($stmt->errorInfo(),true));
		}
		
		$pippo = true;
		$i=0;
		
		$res=array();
		do {
			
			if (isset($pvars['sets'][$i])) {
				$pvars['sets'][$pvars['sets'][$i]] = $this->fetch($stmt);
				unset($pvars['sets'][$i]);
			}
			$i++;
		} while (($pippo=$stmt->nextRowset()));
		
		$stmt->closeCursor();
		$this->getOutVars($pvars['out']);
		
		return $res;
	}
	
	public function fetch($stmt, $how = PDO::FETCH_ASSOC, $what = PDIO::FETCH_ALL) {
		
		switch ($what) {
			case PDIO::FETCH_ALL: $res = $stmt->fetchAll($how); break;
			
			default:	$stmt->fetchAll(PDIO::FETCH_ALL);
		}
		
		return $res;
		
		
	}
	
	private function bindParams(&$stmt, &$pvars) {
		foreach ($pvars['in'] as $k => &$v) {
			if (!$stmt->bindParam(':'.$k, $v)) {
				throw new FWerrorException("PDO MYSQL: error binding in var $k as $v");
			}
		}
			
	}
	
	private function getOutVars(&$outvars) {
		
		$selvars = array();
		
		foreach ($outvars as $k => $v) {
			$selvars[] = '@'.$k." as ".$k;
		}

		$sql = "select ".implode(', ', $selvars);
		$res = $this->query($sql);
		
		foreach ($outvars as $k => &$v) {
			$v  = $res[0][$k];
		}
	}
	
	public function errorInfo() {
		return $this->pdo->errorInfo();
	}
	
	
	public function beginTransaction() {
	    $this->pdo->beginTransaction();
	}
	
	public function rollBack() {
	    $this->pdo->rollBack();
	}
	
	public function commit() {
	    $this->pdo->commit();
	}
	
}


class PDIO_ORA implements PDIO {
	/**
	 * 
	 * @var oci_resource
	 */
	private $conn;
	
	public function __construct() {
		
		
		require_once(TNS_FILE);
		
		
		$this->conn = oci_connect(ORA_UNAME, ORA_PASS, $tnsora['KTSVIL2']);
		
		if (!$this->conn) {
			$e = oci_error();
			throw new FWerrorException("errore connessione oracle: ".$e['message']);
		} 	
		
	}
	
	public function callProcedure($pname, &$pvars){}
	public function errorInfo() {}
	
	public function query($sql, $mode=OCI_ASSOC, $fetch=PDIO::FETCH_ALL){
		
		$mode = $mode | OCI_FETCHSTATEMENT_BY_ROW;
		
		$stmt = oci_parse($this->conn, $sql);
		oci_execute($stmt);
		
		switch ($fetch) {
			case PDIO::FETCH_ALL	: oci_fetch_all($stmt, $res, 0, -1, $mode); break;
			default:	$res = $stmt;
		}
		
		return $res;
	}
	
	public function parametricQuery($sql, $data) {}
	
	
	public function close() {
		oci_close($this->conn);
	}
	
	public function beginTransaction() {
	    $this->pdo->beginTransaction();
	}
	
	public function rollBack() {
	    $this->pdo->rollBack();
	}
	
	public function commit() {
	    $this->pdo->commit();
	}	
	
	
	
}